package com.qdone.module.controller;

import com.linkedin.parseq.Task;
import com.qdone.common.mq.JMSProducer;
import com.qdone.common.util.JwtUtils;
import com.qdone.common.util.Result;
import com.qdone.framework.annotation.RateLimiter;
import com.qdone.framework.core.constant.Constants;
import com.qdone.framework.util.lock.RedisLock;
import com.qdone.framework.util.lock.RedisLockKey;
import com.qdone.framework.util.task.EngineAgent;
import com.qdone.framework.util.task.EngineFactory;
import com.qdone.module.model.Solr;
import com.qdone.module.service.SolrService;
import io.github.swagger2markup.GroupBy;
import io.github.swagger2markup.Language;
import io.github.swagger2markup.Swagger2MarkupConfig;
import io.github.swagger2markup.Swagger2MarkupConverter;
import io.github.swagger2markup.builder.Swagger2MarkupConfigBuilder;
import io.github.swagger2markup.markup.builder.MarkupLanguage;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import org.apache.activemq.command.ActiveMQQueue;
import org.apache.activemq.command.ActiveMQTopic;
import org.apache.commons.io.FileUtils;
import org.asciidoctor.*;
import org.redisson.api.RAtomicLong;
import org.redisson.api.RList;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 高阶功能演示
 */
@Api(tags = "高阶功能演示",description = "高阶功能演示")
@RestController
@RequestMapping("/advance")
public class SwaggerController {

		// 初始任务执行
		static EngineAgent engine = EngineFactory.getEngine(20, 1, 20);
	   
		@Value("${upload.file.dir}")
		private String fileDir;
		
		@Autowired
		private JMSProducer jmsProducer;
		
	    @Autowired
	    private JwtUtils jwtUtils;

		@Autowired
		private RedissonClient redisson;

		@Autowired
		private SolrService solrService;


	    @ApiOperation(value = "在线生成SWAGGER离线文档 ", notes = "生成SWAGGER离线文档,包含:[swagger.html],[swagger.adoc],[swagger.md]文件，请到[页面功能]->[下载功能] 查看文档", httpMethod = "GET", response = Result.class)
		@RequestMapping(value = "/swagger/create", method = RequestMethod.GET)
		@ApiResponse(code = 200, message = "响应请求成功", response = Result.class, responseContainer = "Set")
		public Result<Object> swaggerOffline(
				@ApiParam(required = true, value = "[HTTP]在线JSON地址", name = "url",example="http://114.67.207.106:9090/v2/api-docs?group=InnerApi",defaultValue="http://106.12.24.186:9090/v2/api-docs?group=InnerApi") @RequestParam(value = "url") String url
				) throws MalformedURLException {
	           /**********************1.生成swagger.adoc*****************************/   
	    	   //输出Ascii到单文件
	    		 Swagger2MarkupConfig config = new Swagger2MarkupConfigBuilder()
	    	                .withMarkupLanguage(MarkupLanguage.ASCIIDOC)
	    	                .withOutputLanguage(Language.ZH)
	    	                .withPathsGroupedBy(GroupBy.TAGS)
	    	                .withGeneratedExamples()
	    	                .withoutInlineSchema()
	    	                .build();
	            //url不要使用https方式，否则读取url地址会报错
	    		Swagger2MarkupConverter.from(new URL(url))
	    				.withConfig(config)
	    				.build()
	    				.toFile(Paths.get(fileDir +File.separator+"swagger"));
	    		
	    		//2.生成swagger.html
	    		Asciidoctor asciidoctor = Asciidoctor.Factory.create();
	    		//生成swagger.html配置
	    	    Map<String, Object> attributesMap = new HashMap<String, Object>();
	    	    attributesMap.put("doctype", "book");
	    	    attributesMap.put("toc", "left");//左侧
	    	    attributesMap.put("toclevels", "3");//三级菜单
	    		//参数配置
	    		Attributes attributes = new Attributes();
	    		attributes.setCopyCss(true);
	    		attributes.setLinkCss(false);
	    		attributes.setSectNumLevels(3);
	    		attributes.setAnchors(true);
	    		attributes.setSectionNumbers(true);
	    		attributes.setSourceHighlighter("coderay");
	    		attributes.setHardbreaks(true);
	    		attributes.setTableOfContents(Placement.LEFT);
	    		attributes.setAttribute("generated", fileDir +File.separator+"swagger");
	    		attributes.setAttributes(attributesMap);
	    		OptionsBuilder optionsBuilder = OptionsBuilder.options()
	    		        .backend("html")
	    		        .docType("book")
	    		        .headerFooter(true)
	    		        .eruby("")
	    		        .inPlace(true)
	    		        .safe(SafeMode.UNSAFE)
	    		        .attributes(attributes);
	    		asciidoctor.convertFile(
	    				FileUtils.getFile(fileDir, "swagger.adoc"),
	    		        optionsBuilder.get());
	    		
	    		/**********************2.生成markdown文件*****************************/
	    		//	输出Markdown到单文件
	   		    Swagger2MarkupConfig markDown = new Swagger2MarkupConfigBuilder()
	   	                .withMarkupLanguage(MarkupLanguage.MARKDOWN)
	   	                .withOutputLanguage(Language.ZH)
	   	                .withPathsGroupedBy(GroupBy.TAGS)
	   	                .withGeneratedExamples()
	   	                .withoutInlineSchema()
	   	                .build();
	   		   Swagger2MarkupConverter.from(new URL(url))
	   				.withConfig(markDown)
	   				.build()
	   				.toFile(Paths.get(fileDir +File.separator+"swagger"));	
	   		  return Result.success("文档生成成功! 请移步[页面功能]->[下载功能] 查看文档");
		}
    
	    
	    @ApiOperation(hidden=true,value = "JSON生成SWAGGER文档 ", notes = "JSON生成SWAGGER文档 ,生成的swagger.adoc文件，请到[页面功能]->[下载功能] 页面下载 {swagger.adoc}文件", httpMethod = "POST", response = Boolean.class)
		@RequestMapping(value = "/swagger/build", method = RequestMethod.POST)
		@ApiResponse(code = 200, message = "响应请求成功", response = Solr.class, responseContainer = "Set")
		public Boolean swagger(
				@ApiParam(required = true, value = "生成swagger的json数据", name = "json") @RequestParam(value = "json") String json
				) throws MalformedURLException {
	    	    /*String swaggerJson = restTemplate.getForObject("http://localhost:8089/v2/api-docs", String.class);*/
	            //输出Ascii到单文件
	    		 Swagger2MarkupConfig config = new Swagger2MarkupConfigBuilder()
	    	                .withMarkupLanguage(MarkupLanguage.ASCIIDOC)
	    	                .withOutputLanguage(Language.ZH)
	    	                .withPathsGroupedBy(GroupBy.TAGS)
	    	                .withGeneratedExamples()
	    	                .withoutInlineSchema()
	    	                .build();
	            //url不要使用https方式，否则读取url地址会报错
	    		Swagger2MarkupConverter.from(json)
	    				.withConfig(config)
	    				.build()
	    				.toFile(Paths.get(fileDir +File.separator+"swagger"));
			return true;
		}
    
	    
	    @ApiOperation(value = "sendJmsQueue发送队列消息", notes = "ActiveMq发送队列消息", httpMethod = "POST", response = Boolean.class)
		@RequestMapping(value = "/jms/sendJmsQueue", method = RequestMethod.POST)
		@ApiResponse(code = 200, message = "响应请求成功", response = Boolean.class, responseContainer = "Set")
		public Boolean sendJmsQueue(
				@ApiParam(required = true, value = "发送的消息", defaultValue="boot-master,你好啊！这是示例队列消息！",name = "msg") @RequestParam(value = "msg") String msg
				){
	    	jmsProducer.sendMessage(new ActiveMQQueue("springboot.queue.test"), msg);
			return true;
		}

		@ApiOperation(value = "reciveJmsQueue接收队列消息", notes = "ActiveMq接收队列消息", httpMethod = "POST", response = Boolean.class)
		@RequestMapping(value = "/jms/reciveJmsQueue", method = RequestMethod.POST)
		@ApiResponse(code = 200, message = "响应请求成功", response = Result.class, responseContainer = "Set")
		public Result<Object> reciveJmsQueue() {
			/*List<String> respData=new ArrayList<String>();
			TreeSet<String> keys=jwtUtils.keys(Constants.ActiveMqQueueData.SPRINGBOOT_QUEUE_TEST+"*");
			Iterator<String> it=keys.iterator();
			while(it.hasNext()){
				String value=jwtUtils.get(it.next(), String.class);
				if(!StringUtils.isEmpty(value)){
					respData.add(value);
				}
			}
			return Result.success(respData);*/

			RList<String> list = redisson.getList("redissonQueueList");
			list.expire(30, TimeUnit.MINUTES);//默认30天
			System.err.println(list.remainTimeToLive());
			return Result.success(list.readAll());
		}
	    
	    @ApiOperation(value = "sendJmsTopic发送主题消息", notes = "ActiveMq发送主题消息", httpMethod = "POST", response = Boolean.class)
		@RequestMapping(value = "/jms/sendJmsTopic", method = RequestMethod.POST)
		@ApiResponse(code = 200, message = "响应请求成功", response = Boolean.class, responseContainer = "Set")
		public Boolean sendJmsTopic(
				@ApiParam(required = true, value = "发送的消息", defaultValue="boot-master,你好啊！这是示例主题消息！",name = "msg") @RequestParam(value = "msg") String msg
				){
	    	jmsProducer.publish(new ActiveMQTopic("springboot.topic.test"), msg);
			return true;
		}
	    
	    
	    @ApiOperation(value = "reciveJmsTopic接收主题消息", notes = "ActiveMq接收主题消息", httpMethod = "POST", response = Boolean.class)
		@RequestMapping(value = "/jms/reciveJmsTopic", method = RequestMethod.POST)
		@ApiResponse(code = 200, message = "响应请求成功", response = Result.class, responseContainer = "Set")
		public Result<Object> reciveJmsTopic() {
			/*List<String> respData=new ArrayList<String>();
			TreeSet<String> keys=jwtUtils.keys(Constants.ActiveMqQueueData.SPRINGBOOT_TOPIC_TEST+"*");
			Iterator<String> it=keys.iterator();
			while(it.hasNext()){
				String value=jwtUtils.get(it.next(), String.class);
				if(!StringUtils.isEmpty(value)){
					respData.add(value);
				}
			}
			return Result.success(respData);*/
			RList<String> list = redisson.getList("redissonTopicList");
			return Result.success(list.readAll());
		}

		/**
		 * 测试redisLock
		 * 
		 * @throws InterruptedException
		 *             DistRedisLock:lockKey1lockKey
		 */
		@RequestMapping(value = "/redisLock")
		@ResponseBody
		@RedisLock(lockKey = "lockKey")
		@ApiOperation(value = "Redis分布式锁,简单使用", httpMethod = "POST", notes = "Redis分布式锁,简单使用", response = Boolean.class)
		public Boolean redisLock(
				@ApiParam(required = true, value = "key1", name = "key1",defaultValue="1") @RequestParam(value = "key1") @RedisLockKey(order = 0) int key1,
				@ApiParam(required = true, value = "key2", name = "key2",defaultValue="2") @RequestParam(value = "key2") @RedisLockKey(order = 1) int key2)
				throws InterruptedException {
			System.err.println("开始执行业务逻辑");
			TimeUnit.SECONDS.sleep(20);
			System.err.println("业务逻辑执行完毕");
			return true;
		}
		
		/**
		 * 限流器使用
		 * @param req
		 * @return
		 */
		@ApiOperation(value = "redisson分布式，限流器使用", notes = "redisson分布式，限流器使用", httpMethod = "GET")
		@RequestMapping(value = "/rateLimiter", method = RequestMethod.GET)
		@RateLimiter(limit = 1,timeUnit= Constants.RateLimiterTimeUnit.SECONDS,timeout = 5,rateKey="rateLimiter")
		public Boolean rateLimiter(HttpServletRequest req) {
			System.err.println("rateLimiter");
			return true;
		}

		/**
		 * 使用parseq异步框架
		 * @param req
		 * @return
		 */
		@ApiOperation(value = "ParSeq使用，任务异步并行处理", notes = "ParSeq使用，任务异步并行处理", httpMethod = "GET")
		@RequestMapping(value = "/useParseq", method = RequestMethod.GET)
		@ResponseBody
		public Result<Object> useParseq(HttpServletRequest req) throws InterruptedException {
			// 使用异步处理框架进行处理
			List<Task<List>> taskList = new ArrayList<>();
			// 执行任务
			for (int i = 0; i <10 ; i++) {
				Task<List> task = engine.task(() -> solrService.selectList(null));
				taskList.add(task);
			}
			// 设置2分钟超时
			Task<List<List>> sumResult = Task.par(taskList).withTimeout(2, TimeUnit.MINUTES);
			//运行任务
			engine.run(sumResult);
			// 等待任务执行完成
			sumResult.await();
			// 获取成功的任务
			List res = sumResult.get();
			return Result.success(sumResult.get());
		}


		/**
		 * 远程调用RPC
		 * @return
		 */
		@ApiOperation(value = "redisson远程调用", notes = "redisson远程调用,发送方发送成功，接收方保证接受到发送方的调用，轻量级MQ功能", httpMethod = "GET")
		@RequestMapping(value = "/remoteService", method = RequestMethod.GET)
		public Boolean remoteService() {
			//实例化，服务端redisson和客户端redisson，两端可以分步在不同机器
			RedissonClient server = redisson;
			RedissonClient client = redisson;
			server.getRemoteService().register(RemoteInterface.class, new RemoteImpl());
			RemoteInterface service = client.getRemoteService().get(RemoteInterface.class);
			//参数是分布式自增
			RAtomicLong atomicLong = redisson.getAtomicLong("test");
			Long param=atomicLong.incrementAndGet();
			service.myMethod(param);
			return true;
		}
		/**redisson远程调用，可以保证类似于MQ的方式**/
		public interface RemoteInterface {
			Long myMethod(Long value);
		}
		/**redisson远程调用，可以保证类似于MQ的方式**/
		public  class RemoteImpl implements RemoteInterface {
			public RemoteImpl() {
			}
			@Override
			public Long myMethod(Long value) {
				String msg="Redisson远程调用，本次调用参数是：["+value+"]，服务器处理结果是:["+value*2+"]";
				jmsProducer.sendMessage(new ActiveMQQueue("springboot.queue.test"), msg);
				return value*2;
			}
		}
}
